package com.cskaoyan.javase.thread._5pc._1wait_notify;

/**
 * wait()	void
 * notify()	void
 * notifyAll()	void
 * 1.这三个方法都是Object类的成员方法，理论上Java的所有对象都可以调用这个方法。
 *      这三个方法都是final本地方法，无需考虑它们的具体实现和方法重写。
 *
 * 2.这三个方法的调用者对象都必须是synchronized同步锁对象
 *      否则就会抛出异常——IllegalMonitorStateException。
 *
 * 3.为了能够实现“等待唤醒机制”，这三个方法的调用者应该是同一把锁对象。
 *
 * 首先看一下wait方法的特点:
 *      1.使用的条件
 *      2.执行的特点
 *      3.配合唤醒方法的使用。
 *
 * 使用的条件:
 * 必须是一个sync锁对象调用该方法,否则会抛出异常IllegalMonitorStateException
 *
 * 执行的特点(重点):
 *      1.执行该方法,会让执行位置的线程处于无限等待状态(等待被唤醒,如果不被唤醒就一直等待)
 *      2.(重点)wait阻塞线程后,会不会释放锁?
 *          会释放锁
 *      wait方法执行后,会让执行位置的线程处于无限等待阻塞状态,并且会释放锁对象!
 *
 * @since 10:46
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        final Object o = new Object();
        /*try {
            o.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        /*synchronized (o) {
            // o是一把锁,用它来调用wait方法
            System.out.println("wait before");
            try {
                o.wait();
                System.out.println("wait after");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }*/
        new Thread(() -> {
            synchronized (o) {
                System.out.println("wait before");
                try {
                    o.wait();
                    System.out.println("wait after");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        // 让主线程休眠,下面代码延迟执行,让A线程先启动,保证A先拿到锁对象
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            synchronized (o) {
                System.out.println("B线程拿到了锁对象!");
                System.out.println("B线程执行完毕,释放锁对象!");
            }
        }, "B").start();
    }
}
